package zj.xinxin.business.aop;

import com.alibaba.fastjson.JSON;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import zj.xinxin.api.moudle.system.entity.OptLogEntity;
import zj.xinxin.common.annotation.Log;
import zj.xinxin.common.constant.LogConst;
import zj.xinxin.common.constant.ServiceErrorConst;
import zj.xinxin.common.exception.XinXinException;
import zj.xinxin.common.utils.AssertUtil;
import zj.xinxin.common.utils.IpUtils;
import zj.xinxin.mapper.mapper.system.OptLogEntityMapper;
import zj.xinxin.api.moudle.utils.ConsumerUtil;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Objects;

/**
 * @author junzhou
 * @date 2022/3/23 18:40
 * @since 1.8
 */
@Aspect
@Component
@Slf4j
public class LogAspect {
    @Autowired
    private OptLogEntityMapper optLogMapper;

    /**
     * 日志切入点
     */
    @Pointcut("@annotation(zj.xinxin.common.annotation.Log)")
    public void logPointCut() {
    }

    @Transactional(rollbackFor = XinXinException.class)
    @AfterReturning(value = "logPointCut()", returning = "response")
    public void saveOptLog(JoinPoint joinPoint, Object response) {
        // 获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        // 从获取RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest request = (HttpServletRequest) Objects.requireNonNull(requestAttributes).resolveReference(RequestAttributes.REFERENCE_REQUEST);
        // 从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 获取切入点所在的方法
        Method method = signature.getMethod();
        // 获取操作
        Api api = (Api) signature.getDeclaringType().getAnnotation(Api.class);
        ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
        Log log = method.getAnnotation(Log.class);

        // 获取类名
        String className = joinPoint.getTarget().getClass().getName();
        String name = method.getName();
        String methodName = className + "." + name;


        /*------------------------  数据封装  -----------------------------*/
        OptLogEntity optLog;
        if (log.logType() == LogConst.LOG_TYPE_REGISTER){
            optLog = OptLogEntity.builder()
                    .title(api.tags()[0])
                    .businessType(log.logType())
                    .methodName(apiOperation.value())
                    .methodUrl(methodName)
                    .requestType(Objects.requireNonNull(request).getMethod())
                    .optUrl(request.getRequestURI())
                    .optName("注册用户")
                    .optIp(IpUtils.getIpAddress(request))
                    .optAddress(IpUtils.getIpSource(IpUtils.getIpAddress(request)))
                    .requestParam(JSON.toJSONString(joinPoint.getArgs()))
                    .responseData(JSON.toJSONString(response))
                    .optTime(new Date())
                    .build();

        } else {
            optLog = OptLogEntity.builder()
                    .title(api.tags()[0])
                    .businessType(log.logType())
                    .methodName(apiOperation.value())
                    .methodUrl(methodName)
                    .requestType(Objects.requireNonNull(request).getMethod())
                    .optUrl(request.getRequestURI())
                    .optName(ConsumerUtil.getUserDetails().getNickname())
                    .optIp(IpUtils.getIpAddress(request))
                    .optAddress(IpUtils.getIpSource(IpUtils.getIpAddress(request)))
                    .requestParam(JSON.toJSONString(joinPoint.getArgs()))
                    .responseData(JSON.toJSONString(response))
                    .optTime(new Date())
                    .build();
        }

        int insert = optLogMapper.insert(optLog);
        AssertUtil.sysIsError(insert == 0, ServiceErrorConst.SAVE_DATA_FAIL);
    }
}
